package com.bst.common.utils.security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 对称密钥密码算法工具类
 *
 * @author ruoyi
 */
public class CipherUtils
{



    private static String HEX_STR = "0123456789ABCDEF";
    /**
     * 生成随机秘钥
     *
     * @param keyBitSize 字节大小
     * @param algorithmName 算法名称
     * @return 创建密匙
     */
    public static Key generateNewKey(int keyBitSize, String algorithmName)
    {
        KeyGenerator kg;
        try
        {
            kg = KeyGenerator.getInstance(algorithmName);
        }
        catch (NoSuchAlgorithmException e)
        {
            String msg = "Unable to acquire " + algorithmName + " algorithm.  This is required to function.";
            throw new IllegalStateException(msg, e);
        }
        kg.init(keyBitSize);
        return kg.generateKey();
    }

    public static String getStrKeyAES() throws Exception {
        //密钥生成器,指定生成AES类型的密钥
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        //加密的强随机数
        SecureRandom secureRandom = new SecureRandom(String.valueOf(System.currentTimeMillis()).getBytes("utf-8"));
        //初始化密钥生成器的长度为128位
        keyGen.init(128, secureRandom);   // 这里可以是 128、192、256、越大越安全
        //生成密钥
        SecretKey secretKey = keyGen.generateKey();
        //Base64.getEncoder():使用base64编码来编码字节数据（多加一步更安全）
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    /**
     * 将使用 Base64 加密后的字符串类型的 SecretKey 解码为 SecretKey
     *
     * @param strKey
     * @return SecretKey
     */
    public static SecretKey strKey2SecretKey(String strKey) {
        byte[] bytes = Base64.getDecoder().decode(strKey);
        SecretKeySpec secretKey = new SecretKeySpec(bytes, "AES");
        return secretKey;
    }

    /**
     * 加密
     *
     * @param content   待加密内容
     * @param secretKey 加密使用的 AES 密钥
     * @return 加密后的密文 byte[]
     */
    public static byte[] encryptAES(byte[] content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(content);
    }

    /**
     * 解密
     *
     * @param content   待解密内容
     * @param secretKey 解密使用的 AES 密钥
     * @return 解密后的明文 byte[]
     */
    public static byte[] decryptAES(byte[] content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(content);
    }


    //测试
    public static void main(String args[]) throws Exception {
        //待加密内容
        String str = "bzy.BI2023";
        //获得一个经 BASE64 处理之后的密钥字符串
        String secretKeyStr = getStrKeyAES();
        System.out.println(secretKeyStr);
        //用BASE64方式处理密钥字符串，获取密钥
        SecretKey secretKey = strKey2SecretKey("90jpwyeTWACLU4XxT7zhkA==");
        //获得加密后的内容
        byte[] result = encryptAES(str.getBytes("UTF-8"), secretKey);
        String resultStr = binaryToHexString(result);
        System.out.println("加密后：" +resultStr);
        //将如上内容解密
        try {
            byte[] decryResult = decryptAES(hexStringToBinary(resultStr), secretKey);
            System.out.println("解密后：" + new String(decryResult));
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    public static String binaryToHexString(byte[] bytes){

        String result = "";
        String hex = "";
        for(int i=0;i<bytes.length;i++){
            //字节高4位
            hex = String.valueOf(HEX_STR.charAt((bytes[i]&0xF0)>>4));
            //字节低4位
            hex += String.valueOf(HEX_STR.charAt(bytes[i]&0x0F));

            //result +=" ";
            result +=hex;
        }
        return result;
    }
    public static byte[] hexStringToBinary(String hexString){
        //hexString的长度对2取整，作为bytes的长度
        int len = hexString.length()/2;
        byte[] bytes = new byte[len];
        byte high = 0;    //字节高四位
        byte low = 0;    //字节低四位

        for(int i=0;i<len;i++){
            //左移四位得到高位
            high = (byte)((HEX_STR.indexOf(hexString.charAt(2*i)))<<4);
            low = (byte)HEX_STR.indexOf(hexString.charAt(2*i+1));
            bytes[i] = (byte) (high|low);//高低位做或运算
        }
        return bytes;
    }
}